﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace CrashSimul8or
{
    public sealed partial class PlayGameState : Microsoft.Xna.Framework.DrawableGameComponent
    {
        // SpriteBatch klasinn heldur utan um allt sem þarf að teikna í leiknum, hann hefur fall sem heitir
        // Draw sem teiknar eitthvað á skjáinn þegar Begin hefur verið kallað.
        SpriteBatch spriteBatch;

        // mouseState geymir hvað músin gerði síðast, hvað var ýtt á og hvar á skjánum.
        MouseState mouseState;

        int startGameTime;
        int totalGameTime;
        int numFires;

        // Tiles
        TileMap tiles;
        // Myndavél
        Camera2d camera;
        // Hakk
        int guiSize = 128;
        // Klikk
        ClickHandler click;

        //ParticleEngines
        List<ParticleEngine> particleEngines;
        List<Texture2D> particleTextures;

        // Units er geymt sem listi af units með index [0...i] þar sem það eru i units.
        // Öll Unit t.d. Nurse klasinn erfa frá Unit klasanum þannig að það er hægt að geyma
        // þau öll í þessum lista. Nett.
        List<Unit> units = new List<Unit>();
        // Þessi listi geymir lista yfir þau units sem eru valin, þannig að ef unit númer k í units
        // listanum er valið, þá er k í þessum lista.
        List<int> selectedUnits = new List<int>();

        List<Patient> patients = new List<Patient>();

        int lastScroll = 0;

        public PlayGameState(Game game, SpriteBatch spriteBatch)
            : base(game)
        {
            // Allskonar init dót
            this.spriteBatch = spriteBatch;
            this.tiles = new TileMap(Game.GraphicsDevice);
            this.camera = new Camera2d(tiles.MapWidth, tiles.MapHeight, Game.GraphicsDevice.Viewport.Width, Game.GraphicsDevice.Viewport.Height - guiSize);
            this.click = new ClickHandler();
            GameOverState.clearStats();
            startGameTime = 0;
            totalGameTime = 0;

            //Setja upp particle engines
            particleEngines = new List<ParticleEngine>();
            particleTextures = new List<Texture2D>();
            particleTextures.Add(ResourceManager.getTexture("Circle"));

            //Bæta við eldum (Hilmar þú gætir bætt þessu við í tiles classanum til að hafa staðsetningarnar
            //í samræmi við mappið.
            /*
            particleEngines.Add(new FireParticleEngine(particleTextures, new Vector2(530, 80), 50, 1.1f));
            particleEngines.Add(new FireParticleEngine(particleTextures, new Vector2(900, 430), 50, 1.1f));
            particleEngines.Add(new FireParticleEngine(particleTextures, new Vector2(380, 570), 50, 1.1f));
            particleEngines.Add(new FireParticleEngine(particleTextures, new Vector2(860, 670), 50, 1.1f));
             * */
            Random random = new Random();
            numFires = random.Next(6, 11); //6-10 eldar
            for (int i = 0; i < numFires; i++)
            {
                particleEngines.Add(new FireParticleEngine(
                    particleTextures, 
                    new Vector2(random.Next(400, 1500), random.Next(400, 850)), 
                    25, 1.1f));
            } 
            int numPatients = random.Next(6, 11); //6-10 sjúklingar
            for (int i = 0; i < numPatients; i++)
            {
                patients.Add(new Patient(
                    random.Next(400, 1500), 
                    random.Next(400, 850),
                    random.Next(20, 120))); //30-200 sec í líftíma
            }

            patients.Add(new Patient(400,400,30)); //30-200 sec í líftíma

            Vector2 startZone = new Vector2(200, 200);

            Random rand = new Random();

            // Bæta við björgunarsveitarmönnum
            units.Add(new Rescue(rand.Next((int)startZone.X), rand.Next((int)startZone.Y), particleTextures, patients, 5));
            units.Add(new Rescue(rand.Next((int)startZone.X), rand.Next((int)startZone.Y), particleTextures, patients, 5));
            units.Add(new Rescue(rand.Next((int)startZone.X), rand.Next((int)startZone.Y), particleTextures, patients, 5));
            units.Add(new Rescue(rand.Next((int)startZone.X), rand.Next((int)startZone.Y), particleTextures, patients, 5));

            // Bæta við hjúkkum
            units.Add(new Nurse(rand.Next((int)startZone.X), rand.Next((int)startZone.Y), particleTextures, patients, 15));
            units.Add(new Nurse(rand.Next((int)startZone.X), rand.Next((int)startZone.Y), particleTextures, patients, 15));
            units.Add(new Nurse(rand.Next((int)startZone.X), rand.Next((int)startZone.Y), particleTextures, patients, 29));
            units.Add(new Nurse(rand.Next((int)startZone.X), rand.Next((int)startZone.Y), particleTextures, patients, 29));

            // Bætta við slökkviliðsmönnum
            units.Add(new Fireman(rand.Next((int)startZone.X), rand.Next((int)startZone.Y), particleEngines, particleTextures, 15));
            units.Add(new Fireman(rand.Next((int)startZone.X), rand.Next((int)startZone.Y), particleEngines, particleTextures, 15));
            units.Add(new Fireman(rand.Next((int)startZone.X), rand.Next((int)startZone.Y), particleEngines, particleTextures, 29));
            units.Add(new Fireman(rand.Next((int)startZone.X), rand.Next((int)startZone.Y), particleEngines, particleTextures, 29));


            
        }

        // Update aðferðin er eitthvað sem er kallað á í hvert sinn sem eitthvað gerist, t.d. að skjástærð
        // breytist eða tíminn líður.
        public sealed override void Update(GameTime gameTime)
        {
            // Gummi comment
            if (StateManager.currentState == States.PLAYGAME)
            {
                if (startGameTime == 0)
                {
                    startGameTime = gameTime.TotalGameTime.Seconds;
                }
                else
                {
                    totalGameTime = gameTime.TotalGameTime.Seconds - startGameTime;
                }
                // Ef það er ýtt á Escape þá á leikurinn að pásast.
                if(Keyboard.GetState().IsKeyDown(Keys.Escape))
                {
                    StateManager.currentState = States.PAUSE;
                }

                //Gá hvort leikur er búinn
                int pcount = 0;
                foreach (Patient p in patients)
                {
                    if (!p.isMarked() || (!p.cured && !p.dead))
                    {
                        pcount++;
                    }
                }
                if (particleEngines.Count() == 0 && pcount == 0)
                {
                    int count = 0;
                    foreach (Patient p in patients)
                    {
                        if (p.cured)
                        {
                            count++;
                        }
                    }
                    GameOverState.setStats(patients.Count(), count, numFires, totalGameTime);
                    StateManager.currentState = States.GAMEOVER;
                }

                // Breytur sem geyma breidd og hæð á glugganum
                int Width = Game.GraphicsDevice.Viewport.Width;
                int Height = Game.GraphicsDevice.Viewport.Height;

                foreach (Unit unit in units)
                {
                    unit.Update(gameTime);
                }

                mouseState = Mouse.GetState();

                if (mouseState.ScrollWheelValue != lastScroll)
                {
                    camera.Zoom += -(float)Convert.ToDouble(lastScroll - mouseState.ScrollWheelValue) / 1200;
                }
                lastScroll = mouseState.ScrollWheelValue;

                if (mouseState.X > 0 && mouseState.X < Width && mouseState.Y > 0 && mouseState.Y < Height - 120)
                {
                    if (mouseState.X < 80)
                        ScrollLeft();

                    if (mouseState.X > Width - 80)
                        ScrollRight();

                    if (mouseState.Y < 80)
                        ScrollUp();

                    if (mouseState.Y > Height - guiSize - 80)
                        ScrollDown();
                }

                click.Update(units, selectedUnits, mouseState, Width, Height, camera);

                foreach (ParticleEngine p in particleEngines) p.Update();
                foreach (Patient p in patients) p.Update(gameTime);

            }
        }

        private void ScrollRight()
        {
            camera.Move(new Vector2(6, 0));
        }

        private void ScrollDown()
        {
            camera.Move(new Vector2(0, 6));
        }

        private void ScrollLeft()
        {
            camera.Move(new Vector2(-6, 0));
        }

        private void ScrollUp()
        {
            camera.Move(new Vector2(0, -6));
        }



        public sealed override void Draw(GameTime gameTime)
        {
            if (StateManager.currentState == States.PLAYGAME)
            {
                Vector2[] loc = new Vector2[units.Count];
                int[] rad = new int[units.Count];

                // FYRIR NEÐAN ÞETTA SKAL TEIKNA ALLT
                tiles.beginDrawing(spriteBatch, Game.GraphicsDevice, camera);

                // Teiknum kortið
                tiles.draw(spriteBatch, Game.GraphicsDevice, camera);

                // Teiknum alla sjúklinga
                foreach (Patient p in patients) p.Draw(spriteBatch);

                // Teiknum particles
                foreach (ParticleEngine p in particleEngines) p.Draw(spriteBatch, camera.Pos);

                // Teiknum alla units og hvað þeir sjá langt
                for(int i = 0; i != units.Count; i++)
                {
                    units[i].Draw(spriteBatch);
                    loc[i] = new Vector2(units[i].X, units[i].Y);
                    rad[i] = units[i].Radius;
                }

                // Teiknum hringin sem kemur í kringum units þegar maður velur þau
                foreach (int selectedUnit in selectedUnits) units[selectedUnit].DrawSelection(spriteBatch);
                
                // Teiknum draslið sem kemur þegar maður dregur músina yfir unit
                click.Draw(spriteBatch, mouseState, camera);

                
                // EKKI TEIKNA NEITT FYRIR NEÐAN ÞETTA (Nema að það tilheyrir GUI)
                tiles.endDrawing(spriteBatch, Game.GraphicsDevice, camera);

                // Smá hakk fyrir FOG OF AWESOME
                tiles.drawLight(spriteBatch, Game.GraphicsDevice, camera, loc, rad);
                tiles.drawFogOfWar(spriteBatch, Game.GraphicsDevice, camera);

                // Teiknum GUI
                spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
                tiles.drawGUI(spriteBatch, Game.GraphicsDevice.Viewport.Width, Game.GraphicsDevice.Viewport.Height);
         
                // Teiknum icon fyrir öll units og status fyrir ofan þau.
                for (int i = 0; i != units.Count; i++)
                {
                    spriteBatch.DrawString(ResourceManager.getFont("Arial"), units[i].Status, new Vector2(i * 40, Game.GraphicsDevice.Viewport.Height - 48), Color.Orange);
                    units[i].DrawIcon(spriteBatch, i * 40, Game.GraphicsDevice.Viewport.Height - 32);
                }
                foreach (int selectedUnit in selectedUnits) units[selectedUnit].DrawIconGlow(spriteBatch, selectedUnit * 40, Game.GraphicsDevice.Viewport.Height - 32);


                spriteBatch.DrawString(ResourceManager.getFont("JingJingSmall"), totalGameTime.ToString(), new Vector2((float)(Game.GraphicsDevice.Viewport.Width * 0.95), (float)(Game.GraphicsDevice.Viewport.Height * 0.01)), Color.Orange);
                
                spriteBatch.End();

            }
        }
    }
}